package com.ding.clientserver.controller

import com.ding.clientserver.pojo.Token
import org.json.JSONObject
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.util.LinkedMultiValueMap
import org.springframework.util.MultiValueMap
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.client.RestTemplate
import org.springframework.web.util.UriComponentsBuilder

import javax.servlet.http.HttpSession

@Controller
class AuthenticationController {

    @Autowired
    RestTemplate rest

    //提供一个指向第三方授权中心url地址
    @RequestMapping ('/token')    
    String getCode(Model model, UriComponentsBuilder builder){

  
        String url=builder
                .host('localhost')
                .port(8080)
                .path('/oauth/authorize')
                .toUriString()


        model.addAttribute('url',url)

        model.addAttribute('response_type','code')  //固定值

        model.addAttribute('client_id','ding')      //ClientID

        model.addAttribute('secret','123')          //Client的登录密码

        model.addAttribute('redirect_uri','http://localhost/getToken')  //授权服务器授权成功后重定向的地址

        model.addAttribute('state','这是一些值')               //附加状态,授权服务器向redirect_uri重定向时会将其原封不动地作为参数

        'authorization'
    }


    /*
        使用code向授权服务器换取token
     */

    @RequestMapping ('/getToken')
    @ResponseBody String getToken(String code, String state,@RequestParam(required = false) String error,@RequestParam(required = false) String error_description, HttpSession session){

        //如果授权服务器认证失败error将不会为null
        if (error!=null)
        {
            return "令牌获取失败!原因:"+error+"  问题描述:"+error_description
        }

        //请求头
        HttpHeaders headers=new HttpHeaders();

        //换取token的时候必须使用'Basic '为前缀[clientId]:[secret]经Base64编码的结果作为Authorization请求头
        headers.set('Authorization','Basic '+new String(Base64.encoder.encode("ding:123".getBytes())))


        //请求参数的部分
        MultiValueMap<String, String> variables= new LinkedMultiValueMap<String, String>();
        
        //必须
        variables.add('code',code)                          //授权码
        
        //必须
        variables.add('redirect_uri','http://localhost/getToken')   //重定向uri必须和获取授权的步骤中的一致
        
        //必须
        variables.add('grant_type','authorization_code')              //固定值

        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(variables, headers);

        ResponseEntity<String> r
        try {
            r = rest.exchange('http://localhost:8080/oauth/token', HttpMethod.POST, request, String.class)
        }
        catch (ignored)
        {
            println(ignored)
            return '令牌获取失败'
        }

        println(r.getBody())
        println(state)

        //响应体中将会携带token,将其封装成需要的形式
        JSONObject json=new JSONObject(r.getBody())
        Token token = Token.of(json)
        token.authorization=state


        session.setAttribute("token",token)
        '令牌获取成功'

    }



        /*
            更新令牌

            由于令牌具有时效性,当令牌失效后可以更新令牌

            使用code交换token时除了能够获取token还会获取一个refresh_token,该值是更新令牌的关键
         */
      @RequestMapping('/refresh-token')
      @ResponseBody String refresh(HttpSession session){

        //获取token
        Token token = ((Token) session.getAttribute('token'))

        HttpHeaders headers=new HttpHeaders();

        //依然需要clientId和secret 转换的结果作为Authorization请求头
        headers.set('Authorization',token.authorization)    //以ClientId和secret的Base64编码作为Authorization请求头

        MultiValueMap<String, String> variables= new LinkedMultiValueMap<String, String>();//请求参数
        
        //固定值
        variables.add('grant_type','refresh_token')                        //grant_type必须是refresh_token
        
        //必须
        variables.add('refresh_token',token.refreshToken)                   //refresh_token刷新令牌的值

        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(variables, headers);

        ResponseEntity<String> r

        try {
            r = rest.exchange('http://localhost:8080/oauth/token', HttpMethod.POST, request, String.class)
        }
        catch (ignored)
        {
            println(ignored)
            return '令牌获取失败'
        }

            println(r.getBody())

          token.refresh(new JSONObject(r.getBody()))

        '令牌更新成功'
    }


    /*
        使用令牌访问资源
     */
    @RequestMapping('get/{key}')
    @ResponseBody String get(@PathVariable String key, HttpSession session)
    {
        Token token=(Token)session.getAttribute('token')

        def headers = new HttpHeaders()

        //访问资源提供者时必须携带Authorization请求头
        headers.set('Authorization',token.getToken_type()+" "+token.value)      //必须携带 令牌类型+令牌值 为值的Authorization请求头
        HttpEntity<String> httpEntity=new HttpEntity<>(headers)

        rest.exchange('http://localhost:8080/data/'+key,HttpMethod.GET,httpEntity, String.class).getBody()

    }

}
